/*******************************************************************************
 * Copyright (c) 2010, 2010 Xbeam Project and ChenZhiKong.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 *******************************************************************************/
package org.bellusoft.xbeam.framework;

import java.io.IOException;
import java.net.URL;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

import org.bellusoft.xbeam.framework.BundleStorage.Transaction;
import org.bellusoft.xbeam.framework.XbeamConstants.AutoStartSetting;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleException;
import org.osgi.framework.Version;

/**
 *
 */
class ModuleImpl implements Module{
	
	private Bundle bundle ; 
	
	private BundleStorage storage ; 
	
	private XStartLevel startLevel ; 
	
	private FrameworkEventDispatcher fwkdispatcher ; 
	
	private int state ; 
	
	private boolean lazyStarting ; 
	
	private Condition startedAndStoppedCondition ; 
	
	private Lock lock ; 
	
	private BundleActivator activator ; 
	
	private BundleContext context ; 
	
	private ModuleMetadata metadata ; 
	
	private ModuleLoader loader ; 
	
	public int getState() {
		return state;
	}

	public void start(int options) throws BundleException {
		/**
		 * p 6.1.4.31
		 */
		if(state==Bundle.UNINSTALLED){
			throw new IllegalStateException("Uninstalled bundle cannot be started");
		}
		if(startLevel.isStartLevelSatisfied(bundle)){
			if((((state & Bundle.STARTING)!=0)&&(!lazyStarting))||
					((state & Bundle.STOPPING)!=0)){
				boolean timeout = false ; 
				try{
					//TODO： need wait in a while ? 
					timeout = startedAndStoppedCondition.await(30000, TimeUnit.MILLISECONDS);
				}catch (InterruptedException e) {
					throw new BundleException("Thread to start bundle is interruptted.",e);
				}
				if(timeout){
					throw new BundleException("Bundle start time out.");
				}
			}
			if( (state & Bundle.ACTIVE) != 0){
				return ; 
			}
			if((options & Bundle.START_TRANSIENT)==0){
				persistStartSetting(options);
			}
			if((state & Bundle.RESOLVED) != 0){
				boolean resolved = resolve() ; 
				if(!resolved){
					throw new BundleException("bundle cannot be resolved");
				}
			}
			if((options & Bundle.START_ACTIVATION_POLICY) != 0){
				if(((state & Bundle.STARTING)!=0) && lazyStarting){
					return ; 
				}
				state = Bundle.STARTING ; 
				lazyStarting = true ; 
				publishBundleEvent(BundleEvent.LAZY_ACTIVATION);
				waitForActivationTrigged();
			}
			state = Bundle.STARTING ; 
			startedAndStoppedCondition = lock.newCondition() ; 
			publishBundleEvent(BundleEvent.STARTING);
			try{
				activator = constructBundleActivator() ; 
				if(activator!=null){
					doActivate() ; 
				}
			}catch (Exception e) {
				state = Bundle.STOPPING ; 
				publishBundleEvent(BundleEvent.STOPPING);
				handleActivateException(e);
				state = Bundle.RESOLVED ; 
				publishBundleEvent(BundleEvent.STOPPED);
				throw new BundleException("Error when activating bundle", e);
			}finally{
				startedAndStoppedCondition.signalAll() ; 
			}
			if(state == Bundle.UNINSTALLED){
				throw new BundleException("uninstalled when activate");
			}
			state = Bundle.ACTIVE ; 
			publishBundleEvent(BundleEvent.STARTED) ; 

		}else{
			if((options&Bundle.START_TRANSIENT)!=0){
				throw new BundleException("bundle cannot be started due to the Framework’s current start level");
			}else{
				persistStartSetting(options);
			}
		}
		
	}

	/**
	 * @param e
	 */
	private void handleActivateException(Exception e) {
		// TODO Auto-generated method stub
	}

	/**
	 * @param options
	 * @throws BundleException
	 */
	private void persistStartSetting(int options) throws BundleException {
		Transaction t =  storage.newTranscation();
		try{
			t.begin();
			if((options & Bundle.START_ACTIVATION_POLICY)!=0){
				t.setStartSetting(AutoStartSetting.declared);
			}else{
				t.setStartSetting(AutoStartSetting.eager);
			}
			t.commit();
		}catch(Throwable th){
			try{
				t.rollback();
			}catch (Exception e) {
				//TODO: rollback exception ;
			}
			throw new BundleException("Error when persisting bundle's AutoStartSetting",th);
		}
	}

	/**
	 * @throws Exception 
	 * 
	 */
	private void doActivate() throws Exception {
		activator.start(context);
	}

	private BundleActivator constructBundleActivator() {
		// TODO Auto-generated method stub
		return null;
	}

	private void publishBundleEvent(int event) {
		fwkdispatcher.sendBundleEvent(event);
	}

	/**
	 * 
	 */
	private void waitForActivationTrigged() {
		// TODO Auto-generated method stub
		
	}

	/**
	 * @return
	 */
	private boolean resolve() {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see org.bellusoft.xbeam.framework.Module#start()
	 */
	public void start() throws BundleException {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see org.bellusoft.xbeam.framework.Module#stop(int)
	 */
	public void stop(int options) throws BundleException {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see org.bellusoft.xbeam.framework.Module#stop()
	 */
	public void stop() throws BundleException {
		// TODO Auto-generated method stub
		
	}

	/* (non-Javadoc)
	 * @see org.bellusoft.xbeam.framework.Module#uninstall()
	 */
	public void uninstall() throws BundleException {
		// TODO Auto-generated method stub
		
	}

	public Dictionary<String, String> getHeaders() {
		return metadata.getHeaders();
	}

	public URL getResource(String name) {
		return getLoader().getResource(name);
	}

	public Dictionary<String, String> getHeaders(String locale) {
		return metadata.getHeaders(locale);
	}

	public String getSymbolicName() {
		return metadata.getSymbolicName();
	}

	/* (non-Javadoc)
	 * @see org.bellusoft.xbeam.framework.Module#loadClass(java.lang.String)
	 */
	public Class<?> loadClass(String name) throws ClassNotFoundException {
		return getLoader().loadClass(name);
	}

	/* (non-Javadoc)
	 * @see org.bellusoft.xbeam.framework.Module#getResources(java.lang.String)
	 */
	public Enumeration<URL> getResources(String name) throws IOException {
		return getLoader().getResources(name);
	}

	/* (non-Javadoc)
	 * @see org.bellusoft.xbeam.framework.Module#getEntryPaths(java.lang.String)
	 */
	public Enumeration<String> getEntryPaths(String path) {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see org.bellusoft.xbeam.framework.Module#getEntry(java.lang.String)
	 */
	public URL getEntry(String path) {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see org.bellusoft.xbeam.framework.Module#findEntries(java.lang.String, java.lang.String, boolean)
	 */
	public Enumeration<URL> findEntries(String path, String filePattern,
			boolean recurse) {
		// TODO Auto-generated method stub
		return null;
	}

	public Version getVersion() {
		return metadata.getVersion();
	}

	public boolean isExportPackageUsed() {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see org.bellusoft.xbeam.framework.Module#unresolve()
	 */
	public boolean unresolve() {
		// TODO Auto-generated method stub
	}
	
	private ModuleLoader getLoader(){
		return loader ;
	}

}
